#include "libxluploader.h"
#include <assert.h>
#include <iostream>
#include <limits>

//////////////////////////////////////////////////////////////////////////
// prototypes
static size_t file_put_contents(FILE *file, const std::string &contents);
static bool file_get_contents(FILE *file, std::string &contents);
bool file_get_contentsA(const char *file, std::string &contents);


//////////////////////////////////////////////////////////////////////////
// file PUT/GET contents

size_t file_put_contents(FILE *file, const std::string &contents) {
	assert (file);

	fseek(file, 0, SEEK_SET);
	return fwrite(contents.c_str(), 1, contents.length(), file);
}

size_t file_put_contentsA(const char *file, const std::string &contents) {
	assert (file);
	FILE *s = fopen(file, "wb");
	if (s) {
		size_t ret = file_put_contents(s, contents);
		fclose (s);
		return ret;
	} else {
		return 0;
	}
}

size_t file_put_contents(const TCHAR *file, const std::string &contents) {
	assert (file);
	FILE *s = _tfopen(file, _T("wb"));
	if (s) {
		size_t ret = file_put_contents(s, contents);
		fclose (s);
		return ret;
	} else {
		return 0;
	}
}


bool file_get_contents(FILE *file, std::string &contents) {
	bool ret = false;
	contents = "";

	assert (file);
	fseek(file, 0, SEEK_END);
	long length = ftell(file);
	fseek(file, 0, SEEK_SET);
	if (length > 0) {
		char *buf = new char[length];
		if (buf != NULL) {
			if (fread(buf, 1, length, file) == length) {
				ret = true;
				contents.append(buf, length);
			}
			delete []buf;
			buf = NULL;
		}
	}
	return ret;
}

bool file_get_contents(const TCHAR *file, std::string &contents) {
	assert (file);
	FILE *s = _tfopen(file, _T("rb"));
	if (!s) {
		return false;
	}

	bool ret = file_get_contents(s, contents);

	fclose(s);
	return ret;
}

bool file_get_contentsA(const char *file, std::string &contents) {
	assert (file);
	FILE *s = fopen(file, "rb");
	if (!s) {
		return false;
	}

	bool ret = file_get_contents(s, contents);

	fclose(s);
	return ret;
}


//////////////////////////////////////////////////////////////////////////
std::string util_w2utf8 (const std::wstring &ws) {
	if (ws.length() == 0) {
		return "";
	}

	const wchar_t *src = ws.c_str();
	int u_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
	char *buf = new char[u_len];
	if (!buf) {
		return "";
	}

	WideCharToMultiByte(CP_UTF8, 0, src, -1, buf, u_len, NULL, NULL);

	std::string us = buf;
	delete []buf;
	return us;
}

std::wstring util_mbs2ws (const std::string &mbs) {
	if (mbs.length() == 0) {
		return L"";
	}

	const char *src = mbs.c_str();
	int w_len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
	wchar_t *buf = new wchar_t[w_len];
	if (!buf) {
		return L"";
	}

	MultiByteToWideChar(CP_ACP, 0, src, -1, buf, w_len);

	std::wstring ws = buf;
	delete []buf;
	return ws;
}

tstring util_mbs2tcs(const std::string &mbs) {
#ifdef UNICODE
	return util_mbs2ws(mbs);
#else
	return mbs;
#endif
}


#ifdef max
#undef max
#endif
std::vector<std::string> util_explode(const std::string &delimiter, const std::string &str, int max_parts) {
	if (max_parts == -1) {
		max_parts = std::numeric_limits<int>::max();
	}
	-- max_parts;
	std::vector<std::string> ret;
	std::string s = str;
	int parts = 0;
	while (parts < max_parts) {
		size_t offset = s.find(delimiter);
		if (offset == std::string::npos) {
			break;
		}
		ret.push_back(s.substr(0, offset));
		s = s.substr(offset + delimiter.length());
		++ parts;
	}
	if (s.length() > 0)
		ret.push_back(s);
	return ret;
}


std::string util_get_mime_by_name (const tstring &name) {
	size_t index = name.rfind('.');
	if (index == tstring::npos) {
		return "";
	}

	tstring ext = name.substr(index + 1);
	std::cout << "ext = " << util_w2utf8(ext) << std::endl;
	if (ext.length() == 0) {
		return "";
	}
	const TCHAR *ts = ext.c_str();
	if (_tcsicmp(ts, _T("jpg")) == 0 || _tcsicmp(ts, _T("jpeg")) == 0) {
		return "image/jpeg";
	} else if (_tcsicmp(ts, _T("png")) == 0) {
		return "image/png";
	} else if (_tcsicmp(ts, _T("gif")) == 0) {
		return "image/gif";
	} else if (_tcsicmp(ts, _T("bmp")) == 0) {
		return "image/bmp";
	} else if (_tcsicmp(ts, _T("tif")) == 0 || _tcsicmp(ts, _T("tiff")) == 0) {
		return "image/tiff";
	} else {
		// Add more formats
		return "";
	}
}


std::string util_get_form_action_url (const std::string &form_url, const std::string &action) {
	const char *szFormUrl = form_url.c_str();
	const char *szAction = action.c_str();

	// form url must be a full url
	assert (_memicmp(szFormUrl, "http://", 7) == 0 || _memicmp(szFormUrl, "https://", 8) == 0);
	assert (form_url.length() > 10);

	// if action is empty, use form url
	if (action.length() == 0) {
		return form_url;
	}

	// is action itself a full url?
	if (action.length() >= 8) {
		if (_memicmp(szAction, "http://", 7) == 0 ||
		    _memicmp(szAction, "https://", 8) == 0) {
			return action;
		}
	}

	// is action an absolute path?
	if (action[0] == '/') {
		const char *first_slash = strchr(szFormUrl + 8, '/'); //skip http[s]://
		if (first_slash == NULL) {
			// form_url is like: http://www.google.com, so we just connect form_url and action
			return form_url + action;
		} else {
			// form_url is like: http://www.google.com/
			int offset = first_slash - szFormUrl;
			return form_url.substr(0, offset) + action;
		}
	}

	// action is neither a full url nor absolute path, so it must be a relative path
	const char *last_slash = strrchr(szFormUrl, '/'); // last_slashs can't be NULL, we have :// at last.
	assert (last_slash - szFormUrl > 2);
	if (*(last_slash - 1) == '/') {
		// http://www.google.com
		return form_url + '/' + action;
	} else {
		// http://www.google.com/abc/def/ij
		int offset = last_slash - szFormUrl;
		return form_url.substr(0, offset + 1) + action;
	}
}

bool util_get_form_action_url_test() {
	std::string form_urls[] = {
		"https://www.google.com",
		"http://www.google.com/ncr",
		"http://www.google.com/",
		"http://www.xilou.cn/forum/index.php",
		"http://xilou.cn/forum/",
	};

	std::string actions[] = {
		"/",
		"upload.php",
		"http://www.tinypic.com",
		"/upload.php",
	};

	for (int i = 0; i < COUNT_OF(form_urls); ++ i) {
		for (int j = 0; j < COUNT_OF(actions); ++ j) {
			std::string form_url = form_urls[i];
			std::string action = actions[j];
			std::string result = util_get_form_action_url(form_url, action);

			std::cout << form_url << " + " << action << " =" << std::endl;
			std::cout <<  result << std::endl << std::endl;
		}
	}

	return true;
}


//////////////////////////////////////////////////////////////////////////
// clipboard

std::string util_clipboard_get_html_format(const std::string &fragment, const std::string &src) {
	static std::string startHTML = "StartHTML:00000000\r\n";
	static std::string endHTML = "EndHTML:00000000\r\n";
	static std::string startFragment = "StartFragment:00000000\r\n";
	static std::string endFragment = "EndFragment:00000000\r\n";
	static std::string htmlHeadBegin = "<html><body>\r\n<!--StartFragment-->";
	static std::string htmlHeadEnd = "<!--EndFragment-->\r\n</body>\r\n</html>";
	std::string html = "Version:0.9\r\n";
	html += startHTML;
	html += endHTML;
	html += startFragment;
	html += endFragment;
	if (src.length() > 0){
		html += "SourceURL:";
		html += src;
		html += "\r\n";
	} else {
		html += "SourceURL:http://www.xilou.cn/\r\n";
	}

	size_t html_start = html.length();
	html += htmlHeadBegin;
	size_t fragment_start = html.length();
	html += fragment;
	size_t fragment_end = html.length();
	html += htmlHeadEnd;
	size_t html_end = html.length();
	size_t offset = 0;
	char buf[128];

	sprintf_s(buf, 128, "StartHTML:%08d\r\n", html_start);
	offset = html.find(startHTML);
	assert (offset != std::string::npos);
	html.replace(offset, startHTML.length(), buf);

	sprintf_s(buf, 128, "EndHTML:%08d\r\n", html_end);
	offset = html.find(endHTML);
	assert (offset != std::string::npos);
	html.replace(offset, endHTML.length(), buf);

	sprintf_s(buf, 128, "StartFragment:%08d\r\n", fragment_start);
	offset = html.find(startFragment);
	assert (offset != std::string::npos);
	html.replace(offset, startFragment.length(), buf);

	sprintf_s(buf, 128, "EndFragment:%08d\r\n", fragment_end);
	offset = html.find(endFragment);
	assert (offset != std::string::npos);
	html.replace(offset, endFragment.length(), buf);

	html += '\0';

	return html;
}
